import logging, sys
import threading
from logging.handlers import RotatingFileHandler
from colorlog import ColoredFormatter
from typing import Optional, Callable, Any, Union


class ColorFormatter(logging.Formatter):
    """支持彩色输出的日志格式化器（自动识别是否为终端）"""

    # ANSI 颜色码（仅在终端有效）
    COLOR_CODES = {
        "DEBUG": "\033[94m",  # 蓝色
        "INFO": "\033[92m",  # 绿色
        "WARNING": "\033[93m",  # 黄色
        "ERROR": "\033[91m",  # 红色
        "CRITICAL": "\033[95m",  # 品红
        "RESET": "\033[0m",  # 重置颜色
    }

    def format(self, record: logging.LogRecord) -> str:
        # 如果输出目标不是终端，不使用颜色
        if not getattr(sys.stderr, "isatty", lambda: False)():
            return super().format(record)

        # 根据日志级别添加颜色
        log_level = record.levelname
        color = self.COLOR_CODES.get(log_level, "")
        reset = self.COLOR_CODES["RESET"]

        # 原始格式化逻辑（可自定义格式）
        original_msg = super().format(record)
        return f"{color}{original_msg}{reset}"


# 示例过滤器函数
class LogFilters:
    @staticmethod
    def filter_by_level_max(level: int):
        """只允许<=指定级别的日志"""

        def _filter(record: logging.LogRecord) -> bool:
            return record.levelno <= level

        return _filter

    @staticmethod
    def filter_keywords(keywords: list, case_sensitive=False):
        """过滤包含特定关键词的日志"""

        def _filter(record: logging.LogRecord) -> bool:
            msg = record.getMessage() if case_sensitive else record.getMessage().lower()
            search_space = keywords if case_sensitive else [k.lower() for k in keywords]
            return not any(kw in msg for kw in search_space)

        return _filter

    @staticmethod
    def filter_module(module_names: list):
        """过滤指定模块的日志"""

        def _filter(record: logging.LogRecord) -> bool:
            return record.module not in module_names

        return _filter


class SingletonLogger:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        with cls._lock:
            if not cls._instance:
                cls._instance = super().__new__(cls)
                cls._instance.__initialized = False
        return cls._instance

    def __init__(self, log_file="app.log", enable_file_logging=True):
        if self.__initialized:
            return
        self.__initialized = True

        self.logger = logging.getLogger("SingletonLogger")
        self.logger.setLevel(logging.DEBUG)

        # 控制台日志配置
        self.console_handler = logging.StreamHandler()
        self._setup_console_formatter()
        self.logger.addHandler(self.console_handler)

        # 文件日志配置
        self.file_handler = None
        self.enable_file_logging = enable_file_logging
        self.log_file = log_file
        if self.enable_file_logging:
            self._setup_file_handler()

        # self.add_filter(LogFilters.filter_by_level_max(logging.INFO))

        # 确保线程安全
        self._lock = threading.Lock()
        self._global_filters = []
        self._handler_filters = {}
        # self.add_filter(LogFilters.filter_by_level_max(logging.INFO))

    def _setup_console_formatter(self):
        """配置彩色日志格式"""
        color_format = (
            "%(log_color)s%(asctime)s - "
            "%(levelname)-8s%(reset)s | "
            "%(message_log_color)s%(message)s"
        )
        formatter = ColoredFormatter(
            color_format,
            datefmt="%Y-%m-%d %H:%M:%S",
            reset=True,
            log_colors={
                "DEBUG": "cyan",
                "INFO": "green",
                "WARNING": "yellow",
                "ERROR": "red",
                "CRITICAL": "red,bg_white",
            },
            secondary_log_colors={
                "message": {
                    "DEBUG": "white",
                    "INFO": "white",
                    "WARNING": "yellow",
                    "ERROR": "red",
                    "CRITICAL": "red",
                }
            },
        )
        self.console_handler.setFormatter(formatter)

    def _setup_file_handler(self):
        """配置文件日志切割（按大小）"""
        if self.file_handler:
            self.logger.removeHandler(self.file_handler)

        self.file_handler = RotatingFileHandler(
            filename=self.log_file,
            maxBytes=10 * 1024 * 1024,  # 10MB
            backupCount=5,
            encoding="utf-8",
        )
        # file_formatter = logging.Formatter(
        #     "%(asctime)s - %(levelname)-8s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
        # )

        file_formatter = ColorFormatter(
            fmt="%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
        )
        self.file_handler.setFormatter(file_formatter)
        self.logger.addHandler(self.file_handler)

    def _get_handler(
        self, target: Union[str, logging.Handler]
    ) -> Optional[logging.Handler]:
        """根据名称或实例获取Handler"""
        if isinstance(target, logging.Handler):
            return target if target in self.logger.handlers else None
        elif target == "console":
            return self.console_handler
        elif target == "file":
            return self.file_handler
        return None

    def toggle_file_logging(self, enable: bool):
        """动态切换文件日志开关"""
        with self._lock:
            self.enable_file_logging = enable
            if enable and not self.file_handler:
                self._setup_file_handler()
            elif not enable and self.file_handler:
                self.logger.removeHandler(self.file_handler)
                self.file_handler.close()
                self.file_handler = None

    def add_filter(
        self,
        filter_func: Callable[[logging.LogRecord], bool],
        target: Optional[Union[logging.Handler, str]] = None,
    ):
        """
        添加过滤器

        :param filter_func: 过滤函数，返回True表示保留日志，False表示过滤
        :param target: 指定过滤目标，可选值：
            - None: 应用到Logger全局
            - 'console' 或 'file': 应用到对应Handler
            - Handler实例: 直接应用到指定Handler
        """
        with self._lock:
            if target is None:
                # 全局过滤器
                self.logger.addFilter(lambda record: filter_func(record))
                self._global_filters.append(filter_func)
            else:
                # Handler级别过滤器
                handler = self._get_handler(target)
                if handler:
                    handler.addFilter(lambda record: filter_func(record))
                    self._handler_filters.setdefault(handler, []).append(filter_func)

    def clear_filters(self, target: Optional[Union[logging.Handler, str]] = None):
        """清除过滤器"""
        with self._lock:
            if target is None:
                # 清除全局过滤器
                for filt in self._global_filters:
                    self.logger.removeFilter(filt)
                self._global_filters.clear()
            else:
                # 清除Handler级别过滤器
                handler = self._get_handler(target)
                if handler and handler in self._handler_filters:
                    for filt in self._handler_filters[handler]:
                        handler.removeFilter(filt)
                    self._handler_filters.pop(handler, None)

    def get_logger(self):
        return self.logger


logger = SingletonLogger(
    log_file="app.log",
    enable_file_logging=False,
).get_logger()


def logger_filter_by_level(lvl=logging.INFO):
    SingletonLogger().add_filter(LogFilters.filter_by_level_max(lvl))


def logger_filter_by_keywords(keywords: list):
    SingletonLogger().add_filter(LogFilters.filter_keywords(keywords), target="console")
    # SingletonLogger().add_filter(
    #     LogFilters.filter_keywords(["password", "token"]), target="console"
    # )


def logger_filter_by_modules(modules: list):
    SingletonLogger().add_filter(LogFilters.filter_module(modules), target="console")


def logger_filter_clear(modules: list):
    SingletonLogger().add_filter(LogFilters.filter_module(modules), target="console")


# 使用示例
if __name__ == "__main__":
    # 初始化日志（单例）
    # slogger = SingletonLogger(enable_file_logging=False)
    # logger = slogger.get_logger()

    # logger = SingletonLogger(
    #     log_file="app.log",
    #     enable_file_logging=False,
    # ).get_logger()

    # 测试日志输出
    logger.debug("调试信息")
    logger.info("普通信息")
    logger.warning("警告信息")
    logger.error("错误信息")
    logger.critical("严重错误")

    # 动态关闭文件日志
    SingletonLogger().toggle_file_logging(False)
    logger.info("此消息不会写入文件")

    # 重新启用文件日志
    # SingletonLogger().toggle_file_logging(True)
    # logger.info("此消息将写入文件")

    # 示例1: 全局过滤，只允许INFO及以上级别
    SingletonLogger().add_filter(LogFilters.filter_by_level_max(logging.INFO))

    # 示例2: 控制台过滤敏感词（不区分大小写）
    SingletonLogger().add_filter(
        LogFilters.filter_keywords(["password", "token"]), target="console"
    )

    # 示例3: 文件过滤特定模块
    if SingletonLogger().file_handler:
        SingletonLogger().add_filter(LogFilters.filter_module(["utils"]), target="file")

    # 测试日志
    logger.debug("调试信息（应被全局过滤）")  # 不会输出
    logger.info("普通信息")
    logger.warning(
        "包含Password的警告（控制台过滤）"
    )  # 控制台不显示，文件显示（如果启用文件日志）
    logger.error("Utils模块的错误")  # 文件不记录（如果启用模块过滤）

    # logger.add_filter()
